package jmetal.util.dir;

import jmetal.core.Problem;
import jmetal.core.Solution;
import jmetal.core.SolutionSet;
import jmetal.util.ExtremumPoint;
import jmetal.util.MatrixUtil;
import jmetal.util.SingletonExtremePoint;
import jmetal.util.SingletonReferenceVector;

public class DirFitness {
	private SolutionSet solutionSet;//当前解集
	private int populationSize;//种群数量
	private Problem problem;
	
	public DirFitness(SolutionSet solutionSet, int populationSize,Problem problem){
		this.solutionSet = solutionSet;
		this.populationSize = populationSize;
		this.problem = problem;
	}
	
	public void assignFitness(double delta) {
		int objNum = solutionSet.get(0).getNumberOfObjectives();
		double[][] vectors = SingletonReferenceVector.getReferenceVectors(objNum, populationSize);
		int[] occupyArray = getOccupyCountArray(solutionSet, vectors);
		double[] distanceArray = getDistanceArray(solutionSet);
		
		for(int i = 0;i<solutionSet.size();i++){
			Solution solution = solutionSet.get(i);
			double fitness = distanceArray[i]*delta+1.0/(double)(occupyArray[i]+1.0);
			solution.setFitness(fitness);
		}
	}
	
	/**
	 * 获取到idealpoint距离数组
	 * @param solutionSet
	 * @return
	 */
	private double[] getDistanceArray(SolutionSet solutionSet) {
		double[][] normSolutionMatrix = normSolutionSet(solutionSet);
		double[] distanceArray = new double[solutionSet.size()];
//		double[] idealPoint = ExtremumPoint.getIdealPoint(solutionSet);
		for(int i = 0;i<solutionSet.size();i++){
			double[] normSolutionVector = normSolutionMatrix[i];
			distanceArray[i] = MatrixUtil.norm(normSolutionVector);
		}
		return distanceArray;
	}

	/**
	 * 规范化solutionSet
	 * @param solutionSet
	 * @return
	 */
	private double[][] normSolutionSet(SolutionSet solutionSet) {
		double[] interceptPoint = ExtremumPoint.getInterceptPoint(solutionSet);
		double[] idealPoint = SingletonExtremePoint.getIdealPointInstance(solutionSet);
		int size = solutionSet.size();
		int objNum = solutionSet.get(0).getNumberOfObjectives();
		double[][] normSetMatrix = new double[size][objNum];
		for(int i = 0;i<size;i++){
			Solution solution = solutionSet.get(i);
			for(int j = 0;j<objNum;j++){
				normSetMatrix[i][j] = (solution.getObjective(j)-idealPoint[j])/(interceptPoint[j]-idealPoint[j]);
			}
		}
		return normSetMatrix;
	}
	
	
	/**
	 * 获取绑定参考线个数数组
	 * @param compSet
	 * @param vectors
	 * @return
	 */
	public int[] getOccupyCountArray(SolutionSet compSet, double[][] vectors) {
		int [] counts = new int[compSet.size()];
		double[][] normSolutionMatrix;
		if(problem.getName().startsWith("DTLZ"))
			normSolutionMatrix = solutionSet.writeObjectivesToMatrix();
		else normSolutionMatrix = normSolutionSet(solutionSet);
		for(int i = 0;i<counts.length;i++)
			counts[i] = 0;
		
		for(int i = 0;i<vectors.length;i++){
			int minSub = 0;
			double minAngle = 0;			
			
			for(int j = 0;j<normSolutionMatrix.length;j++){
				double[] objectives = normSolutionMatrix[j];
//				objectives = adaptObjectives(objectives);
				double innerProd = 0;
				for(int dim = 0;dim<vectors[i].length;dim++){
					double x1 = vectors[i][dim];
					double x2 = objectives[dim];
					innerProd =innerProd + (x1*x2);
				}
				double tempAngle = innerProd/ (MatrixUtil.norm(vectors[i])*MatrixUtil.norm(objectives));
					
				if(tempAngle>minAngle){
					minAngle = tempAngle;
					minSub = j;
				}
			}
			counts[minSub]++;
		}
		return counts;
	}

	/**
	 * 绑定角度值
	 */
	public void assignAlgleFitness() {
		int objNum = solutionSet.get(0).getNumberOfObjectives();
		double[][] vectors = SingletonReferenceVector.getReferenceVectors(objNum, populationSize);
		double[] occupyArray = getOccupyValueArray(solutionSet, vectors);
		
		for(int i = 0;i<solutionSet.size();i++){
			Solution solution = solutionSet.get(i);
			double fitness = 1.0/occupyArray[i];
			solution.setFitness(fitness);
		}
	}

	/**
	 * 返回占有的角度值之和
	 * @param solutionSet
	 * @param vectors
	 * @return 
	 */
	private double[] getOccupyValueArray(SolutionSet solutionSet, double[][] vectors) {
		double [] values = new double[solutionSet.size()];
		double[][] solutionNormMatrix;
		for(int i = 0;i<values.length;i++)
			values[i] = 0.000001;
		if(problem.getName().startsWith("DTLZ"))
			solutionNormMatrix = solutionSet.writeObjectivesToMatrix();
		else solutionNormMatrix = normSolutionSet(solutionSet);
		for(int i = 0;i<vectors.length;i++){
			int minSub = 0;
			double minAngle = Double.MAX_VALUE;			
			double[] vector = vectors[i];
			for(int j = 0;j<solutionNormMatrix.length;j++){
//				Solution solution = solutionSet.get(j);
				double[] objectives = solutionNormMatrix[j];
//				double[] idealPoint = SingletonExtremePoint.getIdealPointInstance(solutionSet);
				double tempAngle = MatrixUtil.sin(vector, objectives);
				if(tempAngle < minAngle){
					minAngle = tempAngle;
					minSub = j;
				}
			}
			values[minSub] += Math.sqrt(minAngle);
		}
		return values;
	}
	

}
